#include "MultiGrid.h"

class u_Function1:public Function_one_dim{
public:
    double operator()(const double &x) const {
        return (16*sin(pi*x)+5*sin(16*pi*x));
    }
}u1;

class Function1:public Function_one_dim{
public:
    double operator()(const double &x) const {
        return (16*pi*pi*sin(pi*x)+5*256*pi*pi*sin(16*pi*x));
    }
}f1;

class u_Function2:public Function_one_dim{
public:
    double operator()(const double &x) const {
        return (exp(x)*sin(pi*x)+cos(pi*x/2.0)+x-1.0);
    }
}u2;

class Function2:public Function_one_dim{
public:
    double operator()(const double &x) const {
        return (pi*pi*cos(1.570795*x)/4.0-exp(x)*(2*pi*cos(pi*x)+sin(pi*x)-pi*pi*sin(pi*x)));
    }
}f2;

class u_Function3:public Function_two_dim{
public:
    double operator()(const double &x,const double &y) const {
        return (16*16*(x*x*y*y-x*x*y-x*y*y+x*y));
    }
}u3;

class Function3:public Function_two_dim{
public:
    double operator()(const double &x,const double &y) const {
        return (16*32*y-16*32*y*y);
    }
}f3;

class u_Function4:public Function_two_dim{
public:
    double operator()(const double &x,const double &y) const {
        return (16*sin(pi*x)+5*sin(16*pi*x));
    }
}u4;

class Function4:public Function_two_dim{
public:
    double operator()(const double &x,const double &y) const {
        return (16*pi*pi*sin(pi*x)+5*256*pi*pi*sin(16*pi*x));
    }
}f4;

class u_Function5:public Function_two_dim{
public:
    double operator()(const double &x,const double &y) const {
        return ((exp(y+sin(x))-(1-x)*exp(y)-x*exp(y+sin(1.0))));
    }
}u5;

class Function5:public Function_two_dim{
public:
    double operator()(const double &x,const double &y) const {
        return ((exp(y+sin(x))*(sin(x)-cos(x)*cos(x))));
    }
}f5;

int main() {
    std::cout<<"---------------test_on_one_dimension-----------------"<<std::endl;
    MULTIGRID<1> test1(u1,f1,3,6);
    MULTIGRID<1> test2(u2,f2,3,6);
    MULTIGRID<1> test3(u1,f1,3,6);
    MULTIGRID<1> test4(u2,f2,3,6);
    std::cout<<"Test with V-cycle: "<<std::endl;
    test1.V_cycle();
    test2.V_cycle();
    test1.absolute_error_2norm_print(1);
    test1.relative_error_2norm_print(1);
    test2.absolute_error_2norm_print(2);
    test2.relative_error_2norm_print(2);
    std::cout<<std::endl;
    std::cout<<"Test with FMG: "<<std::endl;
    test3.FMG();
    test4.FMG();
    test3.absolute_error_2norm_print(3);
    test3.relative_error_2norm_print(3);
    test4.absolute_error_2norm_print(4);
    test4.relative_error_2norm_print(4);
    std::cout<<"----------------------test_over-----------------------"<<std::endl;
    std::cout<<std::endl;
    std::cout<<"---------------test_on_two_dimension-----------------"<<std::endl;
    MULTIGRID<2> test5(u3,f3,3,4);
    MULTIGRID<2> test6(u4,f4,3,4);
    MULTIGRID<2> test7(u3,f3,3,4);
    MULTIGRID<2> test8(u4,f4,3,4);
    std::cout<<"Test with V-cycle: "<<std::endl;
    test5.V_cycle();
    test6.V_cycle();
    test5.absolute_error_2norm_print(5);
    test5.relative_error_2norm_print(5);
    test6.absolute_error_2norm_print(6);
    test6.relative_error_2norm_print(6);
    std::cout<<std::endl;
    std::cout<<"Test with FMG: "<<std::endl;
    test7.FMG();
    test8.FMG();
    test7.absolute_error_2norm_print(7);
    test7.relative_error_2norm_print(7);
    test8.absolute_error_2norm_print(8);
    test8.relative_error_2norm_print(8);
    std::cout<<"----------------------test_over-----------------------"<<std::endl;
    std::cout<<std::endl;
    std::cout<<"---------------9.5_II-----------------"<<std::endl;
    MULTIGRID<2> prj9_5_2a(u5,f5,3,4);
    MULTIGRID<2> prj9_5_2b(u5,f5,3,4);
    prj9_5_2a.V_cycle();
    prj9_5_2b.FMG();
    prj9_5_2a.absolute_error_2norm_print(9);
    prj9_5_2a.relative_error_2norm_print(9);
    prj9_5_2b.absolute_error_2norm_print(10);
    prj9_5_2b.relative_error_2norm_print(10);
}



